import axios from 'axios'
import message from './message'
import QS from 'qs'
import { oneOf, typeOf } from './verification'
import { openMask, closeMask } from './mask'
import { loadingBarStart, loadingBarError, loadingBarFinish } from './progress'
import REQUEST_KEY from '../config/request'
import { goLogin, goNoLimits } from '../router'
import { uuid } from './data'
import store from '@/store'
import STATE_KEY from '../config/store'
const CancelToken = axios.CancelToken
const source = CancelToken.source()

const instance = axios.create({
  // baseURL` 将自动加在 `url` 前面，除非 `url` 是一个绝对 URL
  baseURL: REQUEST_KEY.requestParams.prefix,
  withCredentials: REQUEST_KEY.requestParams.withCredentials,
  timeout: REQUEST_KEY.requestParams.timeout,
  cancelToken: source.token
})
/**
 * 响应拦截器
 */
instance.interceptors.response.use((res) => {
  store.commit(STATE_KEY.resetSubmitKey)
  return res
}, (error) => {
  return Promise.reject(error)
})
/**
 * 请求拦截器
 */
instance.interceptors.request.use((res) => {
  const authToken = store.getters.authToken || ''
  if (authToken) {
    res.headers.common.authToken = authToken
  }
  res.headers.common.submitKey = uuid(16, 16)
  return res
}, (error) => {
  return Promise.reject(error)
})
const defaultMethod = {
  /**
   * 获取axios对象
   * @param url 请求地址
   * @param method 请求方法
   * @param requestMode 请求方式
   * @param params 参数配置，遮盖什么的都通过这个参数控制
   * @param responseType 数据返回格式
   * @param config axios相关配置
   */
  getAxiosObj (method, url, params, requestMode, responseType, config) {
    const authToken = store.getters.authToken
    if (url !== '/login') {
      config = {
        headers: {
          authToken
        }
      }
    }
    if (!oneOf(requestMode, Object.values(REQUEST_KEY.requestMode))) {
      message.message.remove()
      message.message.error('请求方式错误')
      return instance()
    }
    if (!oneOf(responseType, Object.values(REQUEST_KEY.responseType))) {
      message.message.remove()
      message.message.error('响应类型错误')
      return instance()
    }
    const object = {
      ...config,
      method,
      url,
      responseType
    }
    if (method !== REQUEST_KEY.requestMethod.get) {
      let formatData = null
      switch (requestMode) {
        case 1:
          formatData = new FormData()
          Object.keys(params).forEach((item) => {
            formatData.append(item, params[item])
          })
          break
        case 2:
          formatData = QS.stringify(params)
          break
        default:
          object.headers = object.headers || {}
          object.headers.submitKey = store.getters.submitKey
          formatData = params
      }
      object.data = formatData
    } else {
      object.params = params
    }
    return instance(object)
  },
  /**
   * 单个请求通过该方法调用baseXhr, 多个请求直接调用baseXhr
   * @param method 请求方法
   * @param url 请求地址
   * @param params 请求参数
   * @param other 请求一些配置，比如是否需要遮盖，成功标识等
   * @param requestMode 请求方式
   * @param responseType 返回方式
   * @param config 配置
   */
  xhr (method, url = '', params = {}, other, requestMode, responseType, config, successCallback = null, errorCallback = null) {
    const obj = this.getAxiosObj(method, url, params, requestMode, responseType, config)
    return this.baseXhr([obj], other, successCallback, errorCallback)
  },
  /**
   * 所有请求调用的都是这个方法，所有的请求都是并发请求
   * @param list
   * @param other
   * @returns {Promise<any>}
   */
  baseXhr (list = [], other, successCallback = null, errorCallback = null) {
    // other必须是一个对象
    if (typeOf(other) === 'object') {
      // 是否开启遮盖
      if (typeOf(other.isCover) !== 'undefined' && other.isCover) {
        openMask()
      }
      if (typeOf(other.code) === 'undefined') {
        other.code = '0'
      }
      if (typeOf(other.data) === 'undefined') {
        other.data = 'data'
      }
      if (typeOf(other.codeText) === 'undefined') {
        other.codeText = 'code'
      }
      if (typeOf(other.isError) !== 'boolean') {
        other.isError = false
      }
      if (typeOf(list) !== 'array' || list.length <= 0) {
        // 暂停程序
        throw new Error('参数传递错误，错误代码1')
      }
      // 使用回调
      if (typeOf(successCallback) === 'function') {
        // 开启进度条
        loadingBarStart()
        // 并发请求
        axios.all(list).then(axios.spread((...response) => {
          const resArray = response.map(res => res[other.data])
          let errorCount = 0
          // 登陆超时判断
          if (resArray.some(item => item[other.codeText] === REQUEST_KEY.requestExpandConfig.timeOutCode)) {
            // 关闭幕布
            closeMask()
            loadingBarError()
            message.message.remove()
            message.message.error('登录超时，3秒后将为你跳转到登录页', { duration: 3 }, () => {
              goLogin()
            })
            // 结束所有请求
            // source.cancel('登录超时')
            return
          }
          if (resArray.some(item => item[other.codeText] === REQUEST_KEY.requestExpandConfig.noLimitsCode)) {
            // 关闭幕布
            closeMask()
            loadingBarError()
            message.message.remove()
            resArray.forEach(item => {
              message.message.error(item.message)
            })
            goNoLimits()
            // 结束所有请求
            // source.cancel('登录超时')
            return
          }
          resArray.forEach(item => {
            if (item[other.codeText] !== other.code) {
              errorCount++
              closeMask()
            }
          })
          if (errorCount < resArray.length) {
            loadingBarFinish()
            successCallback(...resArray)
          } else {
            loadingBarError()
            if (other.isError) {
              // eslint-disable-next-line prefer-promise-reject-errors
              errorCallback(...resArray)
            } else {
              resArray.forEach(item => {
                message.message.error(item.message)
              })
            }
          }
        })).catch((error) => {
          // 到这还出错基本属于接口本身错误或调用错误，这种错误自行处理
          loadingBarError()
          if (other.isCover) {
            closeMask()
          }
          if (other.isError) {
            errorCallback(error)
          } else {
            console.log(error)
          }
        }).finally(() => {
          if (other.isCover) {
            closeMask()
          }
        })
      } /* 使用promise */ else {
        // 并发请求（返回promise）
        return new Promise((resolve, reject) => {
          // 开启进度条
          loadingBarStart()
          // 并发请求
          axios.all(list).then(axios.spread((...response) => {
            const resArray = response.map(res => res[other.data])
            let errorCount = 0
            // 登陆超时判断
            if (resArray.some(item => item[other.codeText] === REQUEST_KEY.requestExpandConfig.timeOutCode)) {
              // 关闭幕布
              closeMask()
              loadingBarError()
              message.message.remove()
              message.message.error('登录超时，3秒后将为你跳转到登录页', { duration: 3 }, () => {
                goLogin()
              })
              // 结束所有请求
              // source.cancel('登录超时')
              return
            }
            if (resArray.some(item => item[other.codeText] === REQUEST_KEY.requestExpandConfig.noLimitsCode)) {
              // 关闭幕布
              closeMask()
              loadingBarError()
              message.message.remove()
              resArray.forEach(item => {
                message.message.error(item.message)
              })
              goNoLimits()
              // 结束所有请求
              // source.cancel('登录超时')
              return
            }
            resArray.forEach(item => {
              if (item[other.codeText] !== other.code) {
                errorCount++
                closeMask()
              }
            })
            if (errorCount < resArray.length) {
              loadingBarFinish()
              resolve(...resArray)
            } else {
              loadingBarError()
              if (other.isError) {
                // eslint-disable-next-line prefer-promise-reject-errors
                reject(...resArray)
              } else {
                resArray.forEach(item => {
                  message.message.error(item.message)
                })
              }
            }
          })).catch((error) => {
            // 到这还出错基本属于接口本身错误或调用错误，这种错误自行处理
            loadingBarError()
            if (other.isCover) {
              closeMask()
            }
            if (other.isError) {
              reject(error)
            } else {
              console.log(error)
            }
          }).finally(() => {
            if (other.isCover) {
              closeMask()
            }
          })
        })
      }
    } else {
      throw new Error('参数传递错误，错误代码2')
    }
  }
}
/**
   * 获取axios对象
   * @param method
   * @param url
   * @param params
   * @param requestMode
   * @param responseType
   * @param config
   */
export function requestObject (url, params, method = REQUEST_KEY.requestMethod.get, responseType = REQUEST_KEY.responseType.json, requestMode = REQUEST_KEY.requestMode.json, config = {}) {
  return defaultMethod.getAxiosObj(method, url, params, requestMode, responseType, config)
}
/**
   * 并发请求
   * @param list axios数组
   * @param other 相关配置
   */
export function requestAll (list, other = REQUEST_KEY.requestConfig, successCallback = null, errorCallback = null) {
  return defaultMethod.baseXhr(list, other, successCallback, errorCallback)
}

/**
 * 请求
 * @param method
 * @param url
 * @param params
 * @param other
 * @param requestMode
 * @param responseType
 * @param config
 * @returns {*|void}
 */
export function request (url, params, method = REQUEST_KEY.requestMethod.get, requestMode = REQUEST_KEY.requestMode.json, responseType = REQUEST_KEY.responseType.json, other = REQUEST_KEY.requestConfig, config = {}, successCallback = null, errorCallback = null) {
  return defaultMethod.xhr(method, url, params, other, requestMode, responseType, config, successCallback, errorCallback)
}

/**
 * get请求
 * @param url
 * @param params
 * @param other
 * @param requestMode
 * @param responseType
 * @param config
 * @param method
 * @returns {*}
 */
export function requestGet (url, params, responseType = REQUEST_KEY.responseType.json, other = REQUEST_KEY.requestConfig, config = {}, requestMode = REQUEST_KEY.requestMode.json, successCallback = null, errorCallback = null, method = REQUEST_KEY.requestMethod.get) {
  return defaultMethod.xhr(method, url, params, other, requestMode, responseType, config, successCallback, errorCallback)
}

/**
 * post请求
 * @param url
 * @param params
 * @param requestMode
 * @param other
 * @param responseType
 * @param config
 * @param method
 * @returns {*}
 */
export function requestPost (url, params, requestMode = REQUEST_KEY.requestMode.json, responseType = REQUEST_KEY.responseType.json, other = REQUEST_KEY.requestConfig, config = {}, successCallback = null, errorCallback = null, method = REQUEST_KEY.requestMethod.post) {
  return defaultMethod.xhr(method, url, params, other, requestMode, responseType, config, successCallback, errorCallback)
}

/**
 * put请求
 * @param url
 * @param params
 * @param requestMode
 * @param other
 * @param responseType
 * @param config
 * @param method
 * @returns {*}
 */
export function requestPut (url, params, requestMode = REQUEST_KEY.requestMode.json, responseType = REQUEST_KEY.responseType.json, other = REQUEST_KEY.requestConfig, config = {}, successCallback = null, errorCallback = null, method = REQUEST_KEY.requestMethod.put) {
  return defaultMethod.xhr(method, url, params, other, requestMode, responseType, config, successCallback, errorCallback)
}

/**
 * delete请求
 * @param url
 * @param params
 * @param requestMode
 * @param other
 * @param responseType
 * @param config
 * @param method
 * @returns {*}
 */
export function requestDelete (url, params, requestMode = REQUEST_KEY.requestMode.json, responseType = REQUEST_KEY.responseType.json, other = REQUEST_KEY.requestConfig, config = {}, successCallback = null, errorCallback = null, method = REQUEST_KEY.requestMethod.delete) {
  return defaultMethod.xhr(method, url, params, other, requestMode, responseType, config, successCallback, errorCallback)
}
